import _ from 'lodash';
import Promise from 'promise';
import validator from 'validator';
import { apiPrefix } from '../../config';
import config from '../config';
import * as at from '../common/at';
import * as tools from '../common/tools';
import markdown from '../common/markdown';
import upFile from '../common/upFile';
import logger from '../common/logger';
import getPages from '../common/pages';
import * as ResultMsg from '../constrants/ResultMsg';
import { errorJson, successJson } from '../common/response';
import { checkId,
         checkName,
         checkDoc,
         checkDocs,
         checkTopicOperateLimit } from '../common/check';
import { UserProxy, TopicProxy, TopicCollectProxy } from '../proxy';
import { UserModel } from '../models';

export {
  checkStatus,
  topics,
  userTopics,
  collectTopics,
  data,
  create,
  update,
  del,
  top,
  good,
  lock,
  collect,
  delCollect,
  status,
  upload,
};

function checkStatus(req, res, next) {
  successJson(req, res, { data: { checkStatus: tools.getTopicStatus() } });
}

async function topics(req, res, next) {
  const appId = res.locals.appId;
  const zoneId = req.body.zoneId || '';
  const currentPage = parseInt(req.body.currentPage, 10) || 1;
  const menuKey = req.body.menuKey || 'all';
  const submenuKey = req.body.submenuKey || '';
  const status = req.body.status || 'reviewed';
  let good = req.body.good || false;
  good = validator.isBoolean(good) ? validator.toBoolean(good) : false;

  if (zoneId === '') {
    return errorJson(req, res, { err: 'zoneId not found!' });
  }

  if (menuKey === '') {
    return errorJson(req, res, { err: '没选菜单' });
  }

  // 获取菜单查询条件
  const conditions = {};
  if (menuKey !== 'all') {
    conditions.menu = menuKey;
  }

  if (submenuKey !== '') {
    conditions.submenu = submenuKey;
  }

  if (status !== 'all') {
    conditions.status = status;
  }

  if (good) {
    conditions.good = good;
  }

  conditions.zoneId = zoneId;
  conditions.appId = appId;

  const limit = config.list_topic_count;
  const options = { skip: (currentPage - 1) * limit, limit, sort: '-top -last_reply_at' };

  try {
    const count = await getPages(TopicProxy.count, conditions, 'pages');
    const topics = await TopicProxy.find(appId, conditions, options);

    const pages = Math.ceil(count / limit);

    const authorIds = [];
    topics.forEach((item) => {
      if (item.author_id) authorIds.push(item.author_id.toString());
    });

    const authors = await UserProxy.findByIds(appId, authorIds);
    successJson(req, res, { data: topics, currentPage, pages, authors });
  } catch (err) {
    next(err);
  }
}

async function userTopics(req, res, next) {
  const appId = res.locals.appId;
  const userId = req.params.uid || '';
  const currentPage = parseInt(req.query.currentPage, 10) || 1;
  const limit = config.list_topic_count;
  const options = { skip: (currentPage - 1) * limit, limit, sort: '-top -last_reply_at' };

  try {
    await checkId(userId);
    const conditions = { appId: appId, author_id: userId };
    const topics = await TopicProxy.find(appId, conditions, options);
    const count = await getPages(TopicProxy.count, conditions, 'pages');
    const pages = Math.ceil(count / limit);
    successJson(req, res, { data: topics, pages, currentPage });
  } catch (err) {
    next(err);
  }
}

async function collectTopics(req, res, next) {
  const appId = res.locals.appId;
  const userId = req.params.uid || '';
  const currentPage = req.body.currentPage || 1;

  const conditions = { appId: appId, user_id: userId };
  const limit = config.list_topic_count;
  const options = { skip: (currentPage - 1) * limit, limit, sort: '-_create_at' };
  const zones = res.locals.zones;

  try {
    await checkId(userId);
    const count = await getPages(TopicCollectProxy.count, conditions, `${userId}collect_topics_pages`);
    const pages = Math.ceil(count / limit);
    const topicIds = await TopicCollectProxy.find(appId, conditions, options);
    const docs = [];
    for (let i = topicIds.length - 1; i >=0; i--) {
      let topic = await TopicProxy.findOneById(appId, topicIds[i].topic_id);
      const author = await UserProxy.findOneById(appId, topic.author_id);
      topic = topic.toObject();
      topic.author = author;

      let index = _.findIndex(zones, function(zone) {
        return zone._id.toString() === topic.zoneId.toString();
      });

      topic.zoneKey = zones[index].key;
      topic.zoneIcon = zones[index].icon
      docs.push(topic);
    }

    successJson(req, res, { data: docs, pages, currentPage });
  } catch (err) {
    next(err);
  }
}

async function data(req, res, next) {
  const appId = res.locals.appId;
  const topicId = req.params.tid;

  try {
    await checkId(topicId);
    let topic = await TopicProxy.findFullOneById(appId, topicId);
    topic.mdContent = markdown(topic.linkedContent);
    successJson(req, res, { data: topic });
  } catch (err) {
    next(err);
  }
}

async function create(req, res, next) {
  const zoneKey = req.params.key;
  const zoneTemplate = req.params.template;
  const appId = res.locals.appId;
  const zoneId = req.body.zoneId || '';
  const title = req.body.title || '';
  const menu = req.body.menu || '';
  const submenu = req.body.submenu || '';
  const area = req.body.area || '';
  const content = req.body.content || '';
  const status = req.body.status || 'saved';
  const mdType = req.body.mdType || config.mdType;
  const tags = req.body.tags || [];
  const isHtml = req.body.isHtml || false;
  const advertisingMap = req.body.advertisingMap || '';
  const audioList = req.body.audioList || [];
  const authorId = req.session.user._id;

  if (title === '') {
    return errorJson(req, res, { err: '标题不能为空' });
  }

  if (content === '') {
    return errorJson(req, res, { err: '内容不能为空' });
  }

  if (title.length < 4 ) {
    return errorJson(req, res, { err: '标题太短（需4个字以上）'})
  }

  const data = {
    zoneId,
    title,
    content,
    area,
    menu,
    submenu,
    authorId: req.session.user._id,
    status,
    mdType,
    tags,
    advertisingMap,
    audioList,
    isHtml,
  };

  try {
    const topic = await TopicProxy.create(appId, data);
    await UserProxy.increaseScore(appId, topic.author_id, { topicCount: 1 });
    at.sendMessageToMentionUsers(appId, content, topic._id, authorId);
    successJson(req, res, { url: `${apiPrefix.page}/zone/${zoneKey}/${zoneTemplate}/topic/${topic._id}/show` });
  } catch (err) {
    next(err);
  }
}

async function update(req, res, next) {
  const zoneKey = req.params.key;
  const zoneTemplate = req.params.template;
  const appId = res.locals.appId;
  const topicId = validator.trim(req.params.tid) || '';
  const title = validator.trim(req.body.title) || '';
  const area = validator.trim(req.body.area) || '';
  const menu = validator.trim(req.body.menu) || '';
  const submenu = validator.trim(req.body.submenu);
  const content = validator.trim(req.body.content) || '';
  const status = validator.trim(req.body.status);
  const mdType = validator.trim(req.body.mdType) || config.mdType;
  const tags = validator.trim(req.body.tags) || [];
  const advertisingMap = validator.trim(req.body.advertisingMap) || '';
  const audioList = req.body.audioList || [];
  const isHtml = req.body.isHtml || false;

  if (title === '') {
    return errorJson(req, res, { err: '标题不能为空' });
  }

  if (content === '') {
    return errorJson(req, res, { err: '内容不能为空' });
  }

  if (title.length < 4 ) {
    return errorJson(req, res, { err: '标题太短（需4个字以上）'})
  }

  const isAdmin = req.session.user.isAdmin;
  const currentUserId = req.session.user._id;

  try {
    const topic = await TopicProxy.findOneById(appId, topicId);
    await checkTopicOperateLimit(topic.author_id, isAdmin, currentUserId);
  } catch (err) {
    return errorJson(req, res, { err });
  }

  const data = {
    title,
    area,
    content,
    menu,
    submenu,
    status,
    tags,
    advertisingMap,
    audioList,
    isHtml,
    update_at: new Date(),
  };

  try {
    await TopicProxy.update(appId, topicId, data);
    at.sendMessageToMentionUsers(appId, content, topicId, req.session.user._id);
    successJson(req, res, { url: `${apiPrefix.page}/zone/${zoneKey}/${zoneTemplate}/topic/${topicId}/show` });
  } catch (err) {
    next(err);
  }
}

async function del(req, res, next) {
  const appId = res.locals.appId;
  const topicId = req.params.tid;
  const isAdmin = req.session.user.isAdmin;
  const currentUserId = req.session.user._id;

  try {
    await checkId(topicId);
    const topic = await TopicProxy.findOneById(appId, topicId);
    await checkTopicOperateLimit(topic.author_id, isAdmin, currentUserId);

    const data = {
      deleted: true,
    };

    await TopicProxy.update(appId, topicId, data);
    successJson(req, res, { msg: '已删除' });
  } catch (err) {
    next(err);
  }
}

async function top(req, res, next) {
  const appId = res.locals.appId;
  const topicId = req.params.tid;

  try {
    await checkId(topicId);
    const topic = await TopicProxy.findOneById(appId, topicId);

    const data = {
      top: !topic.top,
    };

    await TopicProxy.update(appId, topicId, data);
    successJson(req, res, { msg: data.top ? '已置顶' : '已取消置顶' });
  } catch (err) {
    next(err);
  }
}

async function good(req, res, next) {
  const appId = res.locals.appId;
  const topicId = req.params.tid;

  try {
    await checkId(topicId);
    const topic = await TopicProxy.findOneById(appId, topicId);

    const data = {
      good: !topic.good,
    };

    await TopicProxy.update(appId, topicId, data);
    successJson(req, res, { msg: data.good ? '已加精' : '已取消加精' });
  } catch (err) {
    next(err);
  }
}

// 锁定主题，不可再回复
async function lock(req, res, next) {
  const appId = res.locals.appId;
  const topicId = req.params.tid;

  try {
    await checkId(topicId);
    const topic = await TopicProxy.findOneById(appId, topicId);

    const data = {
      lock: !topic.lock,
    };

    await TopicProxy.update(appId, topicId, data);
    successJson(req, res, { msg: data.lock ? '已锁定' : '已取消锁定' });
  } catch (err) {
    next(err);
  }
}

async function collect(req, res, next) {
  const appId = res.locals.appId;
  const topicId = req.body.topicId;
  const userId = req.session.user._id;

  try {
    await checkId(topicId);
    await checkId(userId);
    const collect = await TopicCollectProxy.findOne(appId, userId, topicId);
    if (collect) return errorJson(req, res, { err: '已经收藏' });
    const topic = await TopicProxy.findOneById(appId, topicId);
    if (!topic) return errorJson(req, res, { err: '此话题不存在' });

    let data = {
      collect_count: topic.collect_count + 1,
    };

    await TopicProxy.update(appId, topicId, data);
    await TopicCollectProxy.create(appId, userId, topicId);
    const user = await UserProxy.findOneById(appId, userId);

    data = {
      collect_topic_count: user.collect_topic_count + 1,
    };

    await TopicProxy.update(appId, topicId, data);
    req.session.user.collect_topic_count += 1;
    successJson(req, res, { msg: '成功收藏' });
  } catch (err) {
    next(err);
  }
}

async function delCollect(req, res, next) {
  const appId = res.locals.appId;
  const topicId = req.body.topicId;
  const userId = req.session.user._id;

  try {
    await checkId(topicId);
    await checkId(userId);
    await TopicCollectProxy.remove(appId, userId, topicId);

    const topic = await TopicProxy.findOneById(appId, topicId);
    if (!topic) return errorJson(req, res, { err: '此话题不存在' });
    let data = {
      collect_count: topic.collect_count - 1,
    };
    await TopicProxy.update(appId, topicId, data);

    const user = await UserProxy.findOneById(appId, userId);
    data = {
      collect_topic_count: user.collect_topic_count - 1,
    };
    await TopicProxy.update(appId, topicId, data);

    req.session.user.collect_topic_count -= 1;
    successJson(req, res, { msg: '取消收藏成功' });
  } catch (err) {
    next(err);
  }
}

async function status(req, res, next) {
  const appId = res.locals.appId;
  const topicId = req.params.tid;
  const status = validator.trim(req.body.status) || 'saved';
  const isAdmin = req.session.user.isAdmin;
  const currentUserId = req.session.user._id;

  try {
    await checkId(topicId);
    const topic = await TopicProxy.findOneById(appId, topicId);
    await checkTopicOperateLimit(topic.author_id, isAdmin, currentUserId);

    const data = {
      status: status
    };

    await TopicProxy.update(appId, topicId, data);
    successJson(req, res, { msg: '更新成功' });
  } catch (err) {
    next(err);
  }
}

function upload(req, res, next) {
  let isFileLimit = false;
  req.busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
    file.on('limit', () => {
      isFileLimit = true;

      res.json({
        success: false,
        msg: `File size too large. Max is ${config.file_limit}`,
      });
    });

    upFile(file, { filename }, (err, result) => {
      if (err) {
        return next(err);
      }
      if (isFileLimit) {
        return;
      }
      res.json({
        success: true,
        url: result.url,
      });
    });
  });

  req.pipe(req.busboy);
}
